package com.owen.minio.util.file;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ClassLoaderUtil;
import cn.hutool.core.util.StrUtil;
import com.owen.minio.init.property.MinioProperties;
import com.owen.minio.util.file.entity.FileBean;
import io.minio.*;
import io.minio.errors.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.io.*;
import java.nio.file.Files;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

@Component
public class MinioFileUtils implements FileUtils {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioProperties minioProperties;

    @Override
    public FileBean uploadFile(File file, @NotNull FileBean fileBean) throws IOException {
        return uploadFile(new FileInputStream(file), fileBean);
    }

    @Override
    public FileBean uploadFile(InputStream inputStream, @NotNull FileBean fileBean) throws IOException {
        setContentType(fileBean);
        String bucketName = fileBean.getBucket();
        try {
            createBucket(bucketName);

            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(getObjectPath(fileBean))
                    .stream(inputStream, -1, 10485760)
                    .build();

            fileBean.setAccessUrl(minioProperties.getUrl() + fileBean.getPath() + fileBean.getFileName());

            ObjectWriteResponse objectWriteResponse = minioClient.putObject(putObjectArgs);
            String versionId = objectWriteResponse.versionId();
            fileBean.setVersionId(versionId);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IOException(e);
        }

        return fileBean;
    }

    @Override
    public FileBean uploadFile(byte[] data, @NotNull FileBean fileBean) throws IOException {
        return uploadFile(new ByteArrayInputStream(data), fileBean);
    }

    @Override
    public InputStream downloadFileToStream(FileBean fileBean) throws IOException {
        GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                .bucket(fileBean.getBucket())
                .object(getObjectPath(fileBean))
                .build();
        try {
            return minioClient.getObject(getObjectArgs);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IOException(e);
        }
    }

    @Override
    public byte[] downloadFileToByte(FileBean fileBean) throws IOException {
        InputStream inputStream = downloadFileToStream(fileBean);
        return IoUtil.readBytes(inputStream);
    }

    @Override
    public void downloadFileToFile(FileBean fileBean, File file) throws IOException {
        InputStream inputStream = downloadFileToStream(fileBean);
        OutputStream outputStream = new FileOutputStream(file);
        IoUtil.copy(inputStream, outputStream);
    }

    @Override
    public boolean deleteFile(FileBean fileBean) {
        RemoveObjectArgs removeObjectArgs= RemoveObjectArgs.builder()
                .bucket(fileBean.getBucket())
                .object(getObjectPath(fileBean))
                .build();

        try {
            minioClient.removeObject(removeObjectArgs);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    @Override
    public boolean isFileExists(FileBean fileBean) {
        StatObjectArgs statObjectArgs= StatObjectArgs.builder()
                .bucket(fileBean.getBucket())
                .object(getObjectPath(fileBean))
                .build();

        try {
            StatObjectResponse statObjectResponse = minioClient.statObject(statObjectArgs);
            long size = statObjectResponse.size();
            if(size>0L){
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    private void createBucket(String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket(bucketName).build();
        if (!minioClient.bucketExists(bucketExistsArgs)) {
            MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(bucketName).objectLock(true).build();
            minioClient.makeBucket(makeBucketArgs);
        }
    }

    private String getObjectPath(FileBean fileBean) {
        String path = FileUtil.normalize(fileBean.getPath());
        return path + fileBean.getFileName();
    }


    private void setContentType(FileBean fileBean) {
        if(StrUtil.isEmpty(fileBean.getContentType())){
            try {
                String contentType=null;
                if(ClassLoaderUtil.isPresent("org.springframework.http.MediaTypeFactory")){
                    contentType=MediaTypeFactory.getMediaType(fileBean.getFileName()).orElse(MediaType.APPLICATION_OCTET_STREAM).getType();
                }else{
                    contentType=Files.probeContentType(new File(getObjectPath(fileBean)).toPath());
                }
                fileBean.setContentType(contentType);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

//    /**
//     * downloadObject 会将下载的文件放到当前项目的根目录中
//     * @param fileDownloadBean
//     * @return
//     * @throws IOException
//     */
//    @Override
//    public FileDownloadBean downloadFile(FileDownloadBean fileDownloadBean) throws IOException {
//        DownloadObjectArgs downloadObjectArgs = DownloadObjectArgs.builder()
//                .bucket(fileDownloadBean.getBucket())
//                .object(getObject(fileDownloadBean))
//                .filename(fileDownloadBean.getFileName())
//                .build();
//
//        try {
//            minioClient.downloadObject(downloadObjectArgs);
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw new IOException(e);
//        }
//
//        return fileDownloadBean;
//    }

}
